---
title: Deploy on Fly.io
---

This guide outlines the process of deploying Permify, on Fly.io. We will be using Fly's [deploy with a Dockerfile](https://fly.io/docs/languages-and-frameworks/dockerfile/) functionality.

## Pre-reqs: Install `flyctl`

Before we begin, we need to make sure to have the flyctl command-line utility installed. Install instructions can be [found here.](https://fly.io/docs/flyctl/install/)

## Running with Postgres for persistent storage

### 1. Create a database on Fly

Let's create a semi-managed instance of Postgresql on Fly to store our data so that everything isn't lost when the machines scale down to 0.

Run the command `fly postgres create`, give the new fly app a name, select its location and machine setup. For this example the development configuration was used, but you can choose to make yours highly available with the other options.

```sh
fly postgres create

# output
# Postgres cluster permify-example-psql created
#  Username:    <username>
#  Password:    <password>
#  Hostname:    permify-example-psql.internal
#  Flycast:     fdaa:9:9110:0:1::2
#  Proxy port:  5432
#  Postgres port:  5433
#  Connection string: postgres://<username>:<password>@permify-example-psql.flycast:5432
```

Keep username and password in a secure location like a secrets manager. We'll need the connection string as well in order to connect to our database.

### 2. Create a simple Dockerfile or use the base image directly

Due to limitations with the flyctl command of `fly deploy`, we can't alter the entrypoint or run command from `fly deploy` so we need to directly create our fly machines

To create them directly we can use a Dockerfile which we'll simplify to a single line:

```dockerfile
FROM ghcr.io/permify/permify:latest
```

### 3. Create a new Fly App and configure the services

Create a new fly app with the `fly launch` command and edit the `fly.toml` file that gets created:

```toml
# fly.toml app configuration file generated
#
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
app = 'permify-fly-deploy-with-postgres'
primary_region = 'lax'

[experimental]
  # you'll want to avoid committing the actual username and password in source control for your database
  # and possibly generate this file in a build process to deploy to inject your database secrets.
  cmd = ["serve", "--database-engine=postgres", "--database-uri=postgres://<username>:<password>@permify-psql.flycast:5432"]

[[services]]
  internal_port = 3476
  protocol = 'tcp'
  auto_stop_machines = 'stop'
  auto_start_machines = true
  min_machines_running = 1
  processes = ['app']

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 3476

[[services]]
  internal_port = 3478
  protocol = 'tcp'
  auto_stop_machines = 'stop'
  auto_start_machines = true
  min_machines_running = 1
  processes = ['app']

  [services.ports]
  # we don't need any handlers for this one since the permify grpc server
  # handles tls termination for us.
    port = 3478
    tls_options = { "alpn" = ["h2"] }

[[vm]]
  memory = '1gb'
  cpu_kind = 'shared'
  cpus = 1
```

### 4. Deploy to fly

With the configuration setup, we can now deploy our container to fly

Run the command in the directory with our `Dockerfile` and `fly.toml` configuration:
```sh
fly deploy
```

## Running Permify on Fly without a database

### 1. Create a simple project within a directory

We're going to setup a simple git repository to store our configuration for Fly.io and a simple Dockerfile to deploy.

```sh
mkdir permify-fly-deploy
cd permify-fly-deploy
```

### 2. Create a Dockerfile

Let's create a Dockerfile that uses the latest container image from the Github Registry. We'll set it up to just run the command `serve` in order to run the container without any additional configuration.

```dockerfile
# file: ./permify-fly-deploy/Dockerfile
FROM ghcr.io/permify/permify:latest
CMD ["serve"]
```

### 3. Setup the fly configuration

Next step is to configure our app to run on Fly. Run the command `fly launch` to get an initial configuration setup and generate a basic `fly.toml` file. You can tweak the default configurations to change Region, App Machines, Memory, etc.

```sh
fly launch

# output for basic configuration:
#
# Organization: Your Organization            (fly launch defaults to the personal org)
# Name:         permify-fly-deploy           (derived from your directory name)
# Region:       Los Angeles, California (US) (this is the fastest region for you)
# App Machines: shared-cpu-1x, 1GB RAM       (most apps need about 1GB of RAM)
# Postgres:     <none>                       (not requested)
# Redis:        <none>                       (not requested)
# Tigris:       <none>                       (not requested)

```

### 4. Edit the Fly configuration to expose our ports and service

We'll need to tweak the default configuration generated for us by the `flyctl` command `fly launch` to get our app working. We'll remove the generated section `[http_service]` and add two `[[services]]` sections to our configuration.
This is so we can expose both the REST API and gRPC ports of `3476` and `3478`. If you only want to expose one or the other, then keep only the port service that you wish to expose.

```toml
# fly.toml
app = 'permify-fly-deploy'
primary_region = 'lax'

[experimental]
  allowed_public_ports = [3476, 3478]
  auto_rollback = true

[[services]]
  internal_port = 3476
  protocol = 'tcp'
  auto_stop_machines = 'stop'
  auto_start_machines = true
  min_machines_running = 0
  processes = ['app']

  [[services.ports]]
    handlers = ["tls", "http"]
    port = 3476

[[services]]
  internal_port = 3478
  protocol = 'tcp'
  auto_stop_machines = 'stop'
  auto_start_machines = true
  min_machines_running = 0
  processes = ['app']

  [[services.ports]]
  # we don't need http handlers for our fly machines for port 3478 since our gRPC server handles
  # tls termination for us
  port = 3478

[[vm]]
  memory = '1gb'
  cpu_kind = 'shared'
  cpus = 1
```

### 5. Deploy your fly app

Now we can deploy our service to Fly by using the command `fly deploy`. Once it's done building and the status is showing as deployed, you can check the url provided by Fly to your app in your web browser if the REST API port was exposed by checking the health endpoint `https://<your-app-url>:3476/healthz` and you should see `{"status":"SERVING"}`.

### Example repository
Example configurations for this can be found [https://github.com/theoriginalstove/permify-fly-deploy-example](https://github.com/theoriginalstove/permify-fly-deploy-example)
